package controller

import (
	"encoding/json"
	"fmt"
	_ "html"
	"log"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"time"
	"traffic/system"
	"traffic/utils"

	"github.com/garyburd/redigo/redis"
)

func Click(w http.ResponseWriter, r *http.Request) {
	redisServ := system.Redis

	//获取AD信息
	adid := r.FormValue("aid")
	if adid == "" {
		OutNull(w)
		return
	}
	ad_data, err := getAd(adid)
	if err != nil || len(ad_data) == 0 {
		OutNull(w)
		return
	} else {
		adid = ad_data[0]["id"].(string)
	}

	//获取关联规则组
	rules_data, err := getRule(adid)
	if err != nil || len(rules_data) == 0 {
		return
	}

	//获取ad token

	token := ad_data[0]["tokens"].(string)
	tokenm := make(map[string]interface{})
	json.Unmarshal([]byte(token), &tokenm)
	log.Println("json token:", tokenm)

	//解析URL TOKEN
	//	for kurl, _ := range tokenm {
	//		log.Println("jx:", kurl, r.FormValue(kurl))
	//	}

	//				var rule_infos []map[string]interface{}
	//获得所有规则
	var ruleids []interface{}
	rulemap := make(map[string]interface{})
	for _, v := range rules_data {
		ruleids = append(ruleids, v["id"])
		rulemap[v["id"].(string)] = v["visit"]
	}
	rulevisit, _ := json.Marshal(rulemap)
	rulevisits := string(rulevisit) //取得规则是否合格

	json_ruleids, _ := json.Marshal(ruleids)

	visitMap := CreateVisitMap(r, tokenm)
	visitByte, _ := json.Marshal(visitMap)
	visitStr := string(visitByte)

	//遍历规则
	for k, vo := range rules_data {
		rule_res := true
		if rule_id, ok := vo["id"].(string); ok {
			rule_infos, _ := getRuleInfo(rule_id)

			log.Println("规则:", vo["rulename"])

			//获取规则token
			if TokenLogic(r, vo) == false {
				continue
			}

			//后端规则
			for _, v := range rule_infos {
				res := false
				//				fmt.Println(rule_id, " - ", v)
				switch v["ruletype"] {
				case "ip":
					ip := getRealIp(r)
					res = Lip(ip, v["val"], v["logic"])
				case "country":
					ip := getRealIp(r)
					res = Lcountry(ip, v["val"], v["logic"])
				case "referer":
					res = Lreferer(r.Referer(), v["val"], v["logic"])
				case "visit_count":
					res = Lvisitcount(r, v["val"], v["logic"])
				case "header":
					res = Lheader(r, v["val"], v["logic"])
				}

				log.Println("ruleid:", vo["id"], " ", v["ruletype"], ":", v["logic"], " ", v["val"], ":", res)
				if res == false {
					rule_res = res
					break
				}
			}

			if rule_res == false {
				//判断是否为最后一个
				//log.Println("XXX", k, len(rules_data))
				if (len(rules_data) - k) == 1 {
					OutNull(w)
				}
				continue
			}
			//写入访问LOG
			saveid := Save(r, adid, rule_id, "memo", getRealIp(r), vo["visit"].(string), "abc")

			//js判断
			log.Println("jsx:", vo["jsgyro"], vo["jsresolution"])

			//if vo["visit"]==1 &&  (vo["jsgyro"] == "on" || vo["jsresolution"] == "on" ){
			if vo["jsgyro"] == "on" || vo["jsresolution"] == "on" {
				//				log.Println(vo["wapoutjs"])
				adHash := fmt.Sprintf("%s#%s#s%d", adid, json_ruleids, visitStr, time.Now().UnixNano())
				adinfo := fmt.Sprintf("%s#%s#%s#%d#%s", adid, json_ruleids, visitStr, saveid, rulevisits)
				HashStr := "ad-" + adid + ":" + utils.Md5(adHash)
				redisServ.Do("SETEX", HashStr, 6, adinfo)
				//script := fmt.Sprintf("<script>document.write(\"<div id='ob2'></div>\");eval(atob('%s'));Hash=[%s,%s,'%s','%s']</script>", vo["wapoutjs"], adid, json_ruleids, HashStr, r.RequestURI)
				script := fmt.Sprintf("eval(atob('%s'));Hash=[%s,%s,'%s','%s']", vo["wapoutjs"], adid, json_ruleids, HashStr, r.RequestURI)

				w.Write([]byte(script))
				return
			}

			if rule_res == true {
				vmp := make(map[string]interface{})
				for k, v := range visitMap {
					vmp[k] = v
				}
				outhtml := Getadcontent(ad_data[0], vo, vmp, false)
				w.Write([]byte(outhtml))

				return
			}

		}
	}

}

//获取输出
func GetOutput(ruleid string) (map[string]interface{}, error) {

	var outdata map[string]interface{}
	sql := "select * from ads_ruleout where `ruleid` ='" + ruleid + "'"
	data, err := cacheSql(sql)

	if 0 == len(data) {
		return outdata, nil
	}

	//生成输出概率池
	var outs []*map[string]interface{}
	var split int

	for _, v := range data {
		split, err = strconv.Atoi(v["split"].(string))
		utils.Chkerr(err)

		log.Println("spint", split)
		outmap := v
		for i := 0; i < split; i++ {
			outs = append(outs, &outmap)
		}
	}

	randInt := utils.GetRandInt(99)
	outdata = *outs[randInt]
	log.Println("randInt:", randInt)
	return outdata, nil
}

//输出JS
func GetJscode(outhtml string) string {
	outcontent := outhtml
	outcontent = strings.Replace(outcontent, "\n", " ", -1)
	outcontent = strings.Replace(outcontent, "\r", " ", -1)
	htm := []byte(outcontent)
	randNum := utils.GetRandInt(255)

	s := "a=["
	for _, v := range htm {
		w := fmt.Sprint(v)
		d, _ := strconv.Atoi(w)
		s = s + fmt.Sprint(d^randNum, ",")
	}
	s = utils.Substr(s, 0, len(s)-1) + "]"
	s = s + ";for (var i = 0; i < a.length; i++) {document.write(String.fromCharCode(a[i]^ " + strconv.Itoa(randNum) + " ))}"
	return s
}

// 获取广告
func getAd(adid string) ([]map[string]interface{}, error) {
	sql := "select * from ads_ad where `id` ='" + adid + "'"
	ad_data, err := cacheSql(sql)
	return ad_data, err
}

// 获取详情关联规则组
func getRule(adid string) ([]map[string]interface{}, error) {

	sql := "select * from ads_ad_rule as a left join ads_rule as b on a.ruleid=b.id where b.status='on' and  a.adid =" + adid + " order by sort desc"
	rules_data, err := cacheSql(sql)
	return rules_data, err
}

// 获取具体规则详情
func getRuleInfo(ruleid string) ([]map[string]interface{}, error) {
	sql := "select * from ads_ruleinfo where ruleid =" + ruleid + " order by id"
	data, err := cacheSql(sql)
	return data, err
}

//获取真实IP
func getRealIp(r *http.Request) string {
	cur_ip := r.RemoteAddr
	strip := strings.Split(cur_ip, ":")
	ip := strip[0]
	return ip
}

//统计次数判断
func Lvisitcount(r *http.Request, val, logic interface{}) bool {
	ip := utils.Ip2long(getRealIp(r))
	iplen := CountIP(ip)

	log.Println("iplen:", iplen, ":val", val)
	iplenf := strconv.Itoa(iplen)
	log.Println("iplen:", reflect.TypeOf(iplenf), ":val", reflect.TypeOf(val))
	if logic == "veq" {
		if iplenf == val {
			return true
		}
	}
	return false
}

//判断用户头
func Lheader(r *http.Request, val, logic interface{}) bool {

	header := strings.ToLower(r.UserAgent())
	strs := strings.Split(val.(string), ",")

	for _, s := range strs {
		if strings.Contains(header, strings.ToLower(s)) {
			if logic == "veq" || logic == "vin" {
				return true
			}
			if logic == "vneq" || logic == "vnotin" {
				return false
			}

		}
	}

	log.Println("Header:", val, strs)
	return false
}

// 规则判断处理
// 判断类型 logic
func Lip(cur_ip, v_ip, logic interface{}) bool {
	res := false

	if logic == "veq" {
		if cur_ip == v_ip {
			res = true
		}
	}
	if logic == "vneq" {
		if cur_ip != v_ip {
			res = true
		}
	}
	if logic == "vin" || logic == "vnotin" {
		sval := strings.Split(v_ip.(string), ",")
		if logic == "vin" {
			for _, v := range sval {
				if cur_ip != v {
					return false
				}
			}
		}

		if logic == "vnotin" {
			for _, v := range sval {
				if cur_ip == v {
					return false
				}
			}
		}
	}
	return res
}

func Lcountry(cur_ip, val, logic interface{}) bool {
	redisServ := system.Redis
	//	cur_ip = "61.185.208.255" XIAN
	//	cur_ip = "115.20.192.0" //KR

	res := false
	ipstr := cur_ip.(string)
	ipcache := "IpLogic:" + ipstr + logic.(string) + val.(string)
	v, err1 := redis.String(redisServ.Do("GET", ipcache))
	utils.Chkerr(err1)
	if v != "" {

		if v == "true" {
			return true
		} else {
			return false
		}

	} else {

		cur_int_ip := utils.Ip2long(ipstr)

		ip_part_start := cur_int_ip / 16777216
		ip_part_end := ip_part_start + 1

		sql := fmt.Sprintf("select * from geoip_city_%d_%d where start_ip <=%d and end_ip >=%d and country_code in('%s') order by start_ip DESC", ip_part_start, ip_part_end, cur_int_ip, cur_int_ip, val)
		//	log.Println(sql)
		resdata, err := system.Db.Query(sql)
		utils.Chkerr(err)
		if err == nil {
			data := utils.SqlResolve(resdata)
			if logic == "veq" && len(data) > 0 {
				res = true
			}

			if logic == "vneq" && len(data) < 1 {
				res = true
			}

		}
		if res == true {
			redisServ.Do("SETEX", ipcache, 300, "true")
		} else {
			redisServ.Do("SETEX", ipcache, 300, "false")
		}

	}

	return res
}

func OutNull(w http.ResponseWriter) {
	outhtml := "trafficid=null;\ndocument.write('<a href=\"\" ><img src=\"undefined\" /></a>')"
	w.Write([]byte(outhtml))
}

func GetIpinfo(cur_int_ip uint32) map[string]interface{} {
	//cur_ip := "61.185.208.255" //XIAN
	//cur_int_ip = utils.Ip2long(cur_ip)
	rowmap := make(map[string]interface{})
	ipcache := "IpInfo:" + utils.Long2ip(cur_int_ip)
	v, err1 := redis.String(system.Redis.Do("GET", ipcache))
	utils.Chkerr(err1)
	if v != "" {
		if v == "null" {
			return rowmap
		}
		json.Unmarshal([]byte(v), &rowmap)
		return rowmap
	} else {

		ip_part_start := cur_int_ip / 16777216
		ip_part_end := ip_part_start + 1

		sql := fmt.Sprintf("select * from geoip_city_%d_%d where start_ip <=%d and end_ip >=%d  order by start_ip DESC", ip_part_start, ip_part_end, cur_int_ip, cur_int_ip)
		//	log.Println(sql)
		resdata, err := system.Db.Query(sql)
		if err == nil {
			datas := utils.SqlResolve(resdata)
			if len(datas) > 0 {
				rowmap = datas[0]
				jsonByte, _ := json.Marshal(rowmap)
				jsonStr := string(jsonByte)
				system.Redis.Do("SETEX", ipcache, 300, jsonStr)
				return rowmap
			} else {
				system.Redis.Do("SETEX", ipcache, 300, "null")
			}
		}
	}
	return rowmap
}

//判断referer
func Lreferer(cur_referer, val, logic interface{}) bool {
	res := false
	scur_referer := strings.ToLower(cur_referer.(string))
	sval := strings.ToLower(val.(string))

	if logic == "veq" && strings.Contains(scur_referer, sval) == true {
		res = true
	}
	if logic == "vneq" && strings.Contains(scur_referer, sval) == false {
		res = true
	}

	if logic == "vin" || logic == "vnotin" {
		svals := strings.Split(sval, ",")
		for _, v := range svals {
			has := strings.Contains(scur_referer, v)
			if logic == "vin" && has == true {
				res = true
			}
			if logic == "vnotin" && has == false {
				res = true
			}
		}
	}
	return res
}
